
import { _decorator, Component, Node, Sprite, instantiate, resources, Label, math, Prefab, Graphics, Vec2, Vec3, Button, find, Tween } from 'cc';
const { ccclass, property } = _decorator;
// 
import { AStar, Point } from "./AStar";
/**
 * Predefined variables
 * Name = AStartTest
 * DateTime = Sun Mar 27 2022 10:26:49 GMT+0800 (中国标准时间)
 * Author = lamd
 * FileBasename = AStartTest.ts
 * FileBasenameNoExtension = AStartTest
 * URL = db://assets/Scripts/AStartTest.ts
 * ManualUrl = https://docs.cocos.com/creator/3.4/manual/zh/
 *
 */

class Test {
    value: number;
    constructor(v: number) {
        this.value = v;
    };

    do(param: boolean): string[] {
        if (param)
            return ["a", "b", "c"]
    }
}

interface Tile {
    point: Point;
    node: Node;
    lb: Label;
    sp: Sprite;
}

@ccclass('AStartTest')
export class AStartTest extends Component {

    mapData: number[][];

    from: Point; //起始点
    to: Point; //终点

    row: number;//行
    col: number;//列

    aStarProg: AStar;

    // [2]
    // @property
    // serializableDummy = 0;
    path: Point[] = [];
    tiles: Tile[][] = [];

    isShowCoor: boolean;
    xiePassAble: boolean;

    mapNode: Node;
    nodePlayer: Node;
    tipsNode: Node;
    lbBtnXie: Label;

    showTips() {
        this.tipsNode.setPosition(0, -100);
        this.tipsNode.active = true;
        new Tween(this.tipsNode).by(2, { position: new Vec3(0, 200) }).call(() => {
            this.tipsNode.active = false;
        }).start();
    }

    // 开始寻路
    onBtnStart() {
        this.path = this.aStarProg.run(this.from, this.to);

        if (this.path === undefined) {
            this.showTips();
            return;
        }

        let tw = new Tween(this.nodePlayer)
        let self = this;

        for (let i = 1; i < this.path.length; i++) {
            let rc: Point = this.path[i]; // 行列坐标
            let pos: Vec3 = this.getCoor(rc.y, rc.x)

            tw.to(0.2, { position: pos });
            if (i !== this.path.length - 1)
                tw.call(() => {
                    self.tiles[rc.x][rc.y].sp.color = math.Color.RED;
                })
        }

        tw.start();
    }

    onBtnOpenCoor() {
        this.isShowCoor = !this.isShowCoor;
        this.updateTiles();
    }

    start() {
        this.isShowCoor = false;
        this.xiePassAble = false;

        this.mapNode = this.node.getChildByName("NodeTiles");
        this.nodePlayer = this.node.getChildByName("nodePlayer");
        this.tipsNode = this.node.getChildByName("lbTips");

        const canvas: Node = find("Canvas");

        const btnStart: Button = canvas.getChildByName("BtnStart").getComponent(Button);
        const btnRandom: Button = canvas.getChildByName("BtnRandorm").getComponent(Button);
        const btnOpenCoor: Button = canvas.getChildByName("BtnOpenCoor").getComponent(Button);
        const btnXie: Node = canvas.getChildByName("BtnXie");

        this.lbBtnXie = btnXie.getComponentInChildren(Label);

        btnXie.on(Button.EventType.CLICK, () => {
            this.randomEnd(false);
            this.loadMap();
            this.nodePlayer.setPosition(this.getCoor(this.from.y, this.from.x));
            this.xiePassAble = !this.xiePassAble;
            this.aStarProg.changeXiePassAble(this.xiePassAble);

            this.lbBtnXie.string = this.aStarProg.xiePassAble ? "关闭斜穿" : "开启斜穿";
        }, this);
        btnStart.node.on(Button.EventType.CLICK, this.onBtnStart, this);
        btnRandom.node.on(Button.EventType.CLICK, this.onRandomEnd, this);
        btnOpenCoor.node.on(Button.EventType.CLICK, this.onBtnOpenCoor, this);

        this.init();
    }

    init() {
        this.randomEnd(false);
        this.loadMap();
        this.nodePlayer.setPosition(this.getCoor(this.from.y, this.from.x));
        this.drawLine(this.row, this.col);
    }

    // 由行列得到坐标
    getCoor(row: number, col: number): Vec3 {
        return new Vec3((-180 + 18 + (col) * 36), 180 - (18 + (row) * 36));
    }

    drawLine(row: number, column: number) {
        const g = this.getComponentInChildren(Graphics);
        // g.lineWidth = 10;
        // g.fillColor.fromHEX('#ff0000');
        for (let i = 1; i < row; i++) {
            g.moveTo(-180, 180 - (i * 36));
            g.lineTo(180, 180 - (i * 36));
        }

        for (let i = 1; i < column; i++) {
            g.moveTo(-180 + (i * 36), 180);
            g.lineTo(-180 + (i * 36), -180);
        }

        g.close();
        g.stroke();
        g.fill();
    }

    // 随机终点
    onRandomEnd() {
        this.randomEnd(true);
        this.loadMap();
        this.nodePlayer.setPosition(this.getCoor(this.from.y, this.from.x));
    }

    // 随机终点
    randomEnd(isNew: boolean) {
        let arr: number[][];
        arr = [
            [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 1, 1, 1, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
        ]

        this.from = { x: 1, y: 1 };
        this.to = { x: 0, y: 9 };

        this.row = arr.length;
        this.col = arr[0].length;

        while (isNew) {
            this.to = { x: Math.floor(Math.random() * (10)), y: Math.floor(Math.random() * (10)) }
            // console.log(this.to.x, this.to.y);

            if (arr[this.to.y][this.to.x] == 0)
                isNew = false;
        }

        this.mapData = arr;
        this.aStarProg = new AStar(arr);
    }

    // 载入地图
    loadMap() {
        const isInit = this.tiles.length == 0
        console.log("isInit:" + isInit);

        for (let y = 0; y < this.col; y++) {
            for (let x = 0; x < this.row; x++) {
                if (isInit) {
                    if (this.tiles[x] === undefined)
                        this.tiles[x] = [];

                    resources.load("AStar/pfbTile", Prefab, (err, prefab) => {
                        const tileNode = instantiate(prefab);
                        this.mapNode.addChild(tileNode);

                        tileNode.setPosition(this.getCoor(y, x));
                        tileNode.active = true;

                        let lb: Label = tileNode.getComponentInChildren(Label);
                        let sp: Sprite = tileNode.getComponent(Sprite);
                        // console.log("is exist: Sprite" + sp);

                        this.tiles[x][y] = { point: { x: x, y: y }, node: tileNode, sp: sp, lb: lb };
                        this.updateTile(this.tiles[x][y]);
                    });
                }
                else
                    this.updateTile(this.tiles[x][y]);
            }
        }
    }

    updateTile(tile: Tile) {
        const x = tile.point.x;
        const y = tile.point.y;

        tile.lb.string = this.isShowCoor ? x + "," + y : "";

        if (this.from.x === x && this.from.y === y) {
            tile.lb.string = "始";
            tile.sp.color = math.Color.YELLOW;
        } else if (this.to.x === x && this.to.y === y) {
            tile.lb.string = "终";
            tile.sp.color = math.Color.YELLOW;
        } else if (this.mapData[y][x] == 1) {
            tile.sp.color = math.Color.BLUE;
        }
        else
            tile.sp.color = math.Color.WHITE;
    }

    updateTiles() {
        for (let y = 0; y < this.col; y++)
            for (let x = 0; x < this.row; x++)
                this.updateTile(this.tiles[x][y]);
    }


}

/**
 * [1] Class member could be defined like this.
 * [2] Use `property` decorator if your want the member to be serializable.
 * [3] Your initialization goes here.
 * [4] Your update function goes here.
 *
 * Learn more about scripting: https://docs.cocos.com/creator/3.4/manual/zh/scripting/
 * Learn more about CCClass: https://docs.cocos.com/creator/3.4/manual/zh/scripting/decorator.html
 * Learn more about life-cycle callbacks: https://docs.cocos.com/creator/3.4/manual/zh/scripting/life-cycle-callbacks.html


 *
 */
